﻿using System;
using System.Collections.Generic;
using System.Text;
using Mono.Cecil.Cil;

namespace AgregarTrace
{
    public static class FixLabels
    {
        public static void updateReferences(
            Instruction instruction,
            Instruction replaceBy,
            MethodBody  methodBody
        )
        {
            if (methodBody.Instructions.Count > 0)
                FixLabels.updateNormalReferences (
                    methodBody.Instructions,
                    instruction,
                    replaceBy
                );

            if (methodBody.ExceptionHandlers.Count > 0)
                FixLabels.updateTryReferences (
                    methodBody.ExceptionHandlers,
                    instruction,
                    replaceBy
                );
        }

        static void updateNormalReferences (
            IEnumerable<Instruction> collection,
            Instruction oldTarget,
            Instruction newTarget
        )
        {
            foreach (var instrX in collection)
            {
                if (instrX.OpCode == OpCodes.Switch)
                {
                    var operands = (Instruction[]) instrX.Operand;

                    for (int i = 0; i < operands.Length; ++i)
                        if (operands[i] ==  oldTarget)
                            operands[i] =   newTarget;
                }
                else if (instrX.Operand == oldTarget)
                {
                    instrX.Operand = newTarget;
                }
            }
        }

        static void updateTryReferences (
            IEnumerable<ExceptionHandler> handlers,
            Instruction oldTarget,
            Instruction newTarget
        )
        {
            foreach (var handler in handlers)
            {
                if (handler.TryEnd == oldTarget)
                    handler.TryEnd = newTarget;
                if (handler.TryStart == oldTarget)
                    handler.TryStart = newTarget;
                if (handler.HandlerStart == oldTarget)
                    handler.HandlerStart = newTarget;
                if (handler.FilterStart == oldTarget)
                    handler.FilterStart = newTarget;
            }
        }
    }
}
